#!TCLSH_PATH
#
# Usage:
#	rtl2sim.tcl <verilog_rtl_filename> <dir> [<sim_filename>]
#
# If cel_filename is not specified, then name will be the root name
# of the verilog RTL file with the .sim extension.
#
# "dir" is the directory where .sim views of the standard cells are
# located.  If .sim views are not available but .mag files are, the
# .sim files will be generated automatically. 
#
#------------------------------------------------------------
# Original bdnet2sim.tcl Written by Tim Edwards February 12, 2007
# Modified for Verilog RTL input, Tim Edwards, April 25, 2011
#------------------------------------------------------------

set rtlfile [lindex $argv 0]
set cellname [file rootname $rtlfile]
if {"$cellname" == "$rtlfile"} {
   set rtlfile ${cellname}.rtl.v
}

set prefix ""
if {$argc > 2} {
   if {[lindex $argv [expr {$argc - 2}]] == "-prefix"} {
      set prefix [lindex $argv [expr {$argc - 1}]]/
      incr argc -2
   }
}

if {$argc > 1} {
   set magdir [lindex $argv 1]
} else {
   set magdir /home/tim/projects/multigig/digital_flow/layout/digital2
}

if {$argc == 3} {
   set simfile [lindex $argv 2]
} else {
   set simfile ${cellname}.sim
}

set scriptdir [file dirname $argv0]

#-------------------------------------------------------------
# Open files for read and write

if [catch {open $rtlfile r} fnet] {
   puts stderr "Error: can't open file $rtlfile for reading!"
   exit 0
}

#----------------------------------------------------------------
# First, parse the contents of the RTL file and get a list
# of all macro names used.  Use also to get the module name,
# which we will use for the .sim file name.
#----------------------------------------------------------------

puts stdout "1st pass of RTL file ${rtlfile}. . ."
flush stdout

set macrolist {}
while {[gets $fnet line] >= 0} {
   if [regexp {^[ \t]*//} $line lmatch] {
      # Comment line---do nothing
   } elseif [regexp {^module[ \t]+([^ \t]+)[ \t]*\(} $line lmatch cellverify] {
      if {"$cellname" != "$cellverify"} {
	 puts -nonewline stderr "WARNING:  MODEL name ${cellverify} does not"
	 puts stderr " match filename ${cellname}!"
	 set cellname $cellverify
	 if {$argc != 3} {set simfile ${cellname}.sim}
      }
   } elseif [regexp {^[ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]+\(} $line lmatch macro inst] {
      if {"$macro" != "module"} {
         lappend macrolist $macro
      }
   }
}
set macrolist [lsort -unique $macrolist]
close $fnet

set needsims {}
foreach macro $macrolist {
   if {[glob -nocomplain ${magdir}/${macro}.sim] == {}} {
      lappend needsims ${macro}
   } elseif {[file size ${magdir}/${macro}.ext] == 0} {
      lappend needsims ${macro}
   }
}

if {$needsims != {}} {
   puts stdout "Generating .sim views. . ."
   flush stdout

   foreach macro $needsims {
      puts stdout "Generating ${macro}.sim"
      flush stdout
      catch {exec ${scriptdir}/makesim.sh ${magdir}/$macro}
   }
}

if [catch {open $simfile w} fsim] {
   puts stderr "Error: can't open file $simfile for writing!"
   exit 0
}

puts $fsim "| SIM file $simfile generated by rtl2sim"

#----------------------------------------------------------------
# Procedure to dump the contents of a subcircuit .sim file to the
# top-level .sim file, replacing pin names with net names.
#----------------------------------------------------------------

proc dump_sim {fsim mode magdir prefix} {

   # Pick up variable definition from top-level
   upvar $mode mname

   # Make VDD, VSS, and GND show up as globals
   set mname(VDD)  VDD
   set mname(VDD!) VDD
   set mname(VSS)  VSS
   set mname(VSS!) VSS
   set mname(GND)  GND
   set mname(GND!) GND

   puts $fsim "| ${mode} $mname(count) = $mname(instance)"

   set fsub [open ${magdir}/${mode}.sim r]
   while {[gets $fsub line] >= 0} {
      set mtype [string index $line 0]

      # Parse .sim file lines.  Ignore lumped "R", which is not used by IRSIM.

      switch -exact $mtype {
	 n -
	 p { regexp {^[pn] ([^ ]+) ([^ ]+) ([^ ]+) (.*)} $line valid \
			gate drain source rest
	     puts -nonewline $fsim "$mtype "
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${gate}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$gate "
	     }
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${drain}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$drain "
	     }
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${source}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$source "
	     }
	     puts $fsim $rest
	   }  
	 r { regexp {^r ([^ ]+) ([^ ]+) (.*)} $line valid r1 r2 rest
	     puts -nonewline $fsim "r "
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${r1}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$r1 "
	     }
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${r2}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$r2 "
	     }
	     puts $fsim $rest
	   }  
	 C { regexp {^C ([^ ]+) ([^ ]+) (.*)} $line valid top bottom rest
	     puts -nonewline $fsim "C "
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${top}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$top "
	     }
	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${bottom}) "}]} {
		puts -nonewline $fsim "${prefix}$mname(instance)/$bottom "
	     }
	     puts $fsim $rest
	   }  
	 | { puts $fsim $line }
      }
   }
   close $fsub
}

#----------------------------------------------------------------
# Parse the contents of the RTL file again and dump each cell
# instance to the .sim file output.

puts stdout "2nd pass of RTL file. . ."
flush stdout

set fnet [open $rtlfile r]
set mode none
while {[gets $fnet line] >= 0} {
   if [regexp {^[ \t]*//} $line lmatch] {
      # Comment line---do nothing
   } elseif [regexp {^module[ \t]+([^ \t]+)[ \t]*\(} $line lmatch cellverify] {
      if {"$cellname" != "$cellverify"} {
	 puts -nonewline stderr "WARNING:  MODEL name ${cellverify} does not"
	 puts stderr " match filename ${cellname}!"
      }
   } elseif [regexp {^[ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]+\((.*)$} $line \
		lmatch macroname instname rest] {
      # New instance.  First dump the current instance to the sim file
      if {$mode != "pins" && $mode != "none" && $mode != "wires"} {
	 dump_sim $fsim $mode $magdir $prefix
      }
      set mode $macroname
      if {[catch {incr ${mode}(count)}]} {
	 set ${mode}(count) 0
      } else {
	 # Clear pin assignments so that unconnected outputs don't get shorted
	 # to the last instance
	 set qcount [set ${mode}(count)]
	 array unset ${mode}
	 set ${mode}(count) $qcount
      }
      set ${mode}(instance) $instname

      # parse "rest" for any pin information on the first line
      while {[regexp {[ \t]*.([^(]+)\(([^) \t]+)[ \t]*\),*(.*)$} $rest \
		lmatch pinname netname more] > 0} {
	 # puts stderr "pin: ${mode}(${pinname}) $netname"
	 set ${mode}(${pinname}) $netname
	 set rest $more
      }
   } elseif [regexp {^endmodule} $line lmatch] {
      # Dump last "mode" output
      if {$mode != "pins"} { dump_sim $fsim $mode $magdir $prefix}
   } elseif [regexp {^[ \t]*input} $line lmatch] {
      set mode "pins"
   } elseif [regexp {^[ \t]*output} $line lmatch] {
      set mode "pins"
   } elseif [regexp {^[ \t]*wire} $line lmatch] {
      set mode "wires"
   } else {
      while {[regexp {[ \t]*.([^(]+)\(([^) \t]+)[ \t]*\),*(.*)$} $line \
		lmatch pinname netname rest] > 0} {
	 # puts stderr "pin: ${mode}(${pinname}) $netname"
	 set ${mode}(${pinname}) $netname
	 set line $rest
      }
   }
}
# Dump the final instance to the sim file, if there was one.
if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix}
close $fnet

puts stdout "Done!"
